	dappr.extend({

		/*
		 * Request - Asynchronous request hook for Dappr APIs to obtain a.) Permissions and b.) API access
		 */
		request: (function(){
					
			var requestStack = []; // keeps a record of all requests from API methods
		
			/*
			 * Queue a new asynchronous request
			 * 
			 * options MUST include:
			 * 		- successCB,
			 *      - feature
			 *      
			 * options MAY include:
			 *      - errorCB
			 *      - timeout
			 */
			function add$(options) {
				
				// create a request id for this request
				var requestId = generateRequestID();
				
				// add requestId to options
				dappr.extend(options, {requestId: requestId});
				
				// add to request stack
				requestStack.push(options);
				
				// add feature to dialog stack
				dappr.dialog.addFeature(options.feature, dappr.request.onAuthorisedCallback, dappr.request.remove, requestId);				
				
				return requestId;
			}
			
			function generateRequestID(len) {
				var id = '';
				if(!len || typeof len != 'integer' || len<10 || len>32) len = 32;
				for(var i=0; i<len; i++) {
					id += Math.round(Math.random()*9); 
				}
				return id;
			}
			
			/*
			 * Remove an asynchronous request from queue. Fire the errorCB before removal!
			 */
			function remove$(requestId) {
				// 1. retrieve the associated requestId options
				var request = getRequestFromStack(requestId);
				
				if (request) {
					var errorCB = request.options.errorCB;
					
					// remove request from stack...
					dappr.arrayRemove(requestStack, request.index);
										
					// fire the error callback if it exists... (error = CANCELLED)
					if (errorCB) {
						errorCB.call(errorCB, 'CANCELLED');
					}			
				}
			};
			
			function onAuthorisedCallback$(requestId) {
			
				// 1. retrieve the associated requestId options
				var request = getRequestFromStack(requestId);
						
				if(request && request.options) {
					// Actually do the given request:	
					dappr.oauthClient.doRequest(
						request.options.onSuccess, 
						request.options.onError || function(){}, 
						request.options.params,
						request.options.data,
						request.options.timeout
					);
				}
			};
			
			// returns object literal if requestId is found: {options: ... , index: ...}
			function getRequestFromStack(requestId) {
				for(var i=0; i<requestStack.length; i++) {
					if(requestStack[i].requestId == requestId) {						
						return {options: requestStack[i], index: i};							
					}
				}				
				return null;
			};
			
			return {
				add: function(options){
					return add$(options);
				},
				
				remove: function(requestId){
					return remove$(requestId);
				},
				
				onAuthorisedCallback: function(requestId) {
					onAuthorisedCallback$(requestId);
				}
			};
		}())

	});
